{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 神经网络基础笔记\n",
    "\n",
    "神经元的概念来自于生物学中的**神经元**。我们神经网络中的神经元结构上也有生物意义上的**神经元**相类似。但是它们实际上是不一样的，所以习惯是，对于深度学习中的神经元，我们一般简单称为**unit**。\n",
    "我们的神经元大概如下图所示，图片来自于斯坦福cs231n课程笔记：\n",
    "![neuron](images/neuron.png)|![neuron_model](images/neuron_model.jpeg)\n",
    "\n",
    "从第二张图我们可以看出，神经网络的一个单元，做了以下几件事情：\n",
    "\n",
    "* 讲各个输入进行求和（也就是我们的score function的作用）\n",
    "* 对上面的结果，送入一个激励函数，得到输出\n",
    "\n",
    "我们用代码表示这个过程，如下所示：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9088770389851438\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import math\n",
    "\n",
    "\n",
    "def forward(inputs, weights, bias):\n",
    "    sum = np.sum(inputs*weights) + bias\n",
    "    firing_rate = 1.0/(1.0 + math.exp(-sum)) # sigmoid function\n",
    "    return firing_rate\n",
    "\n",
    "print(forward(1.0, 2.0, 0.3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面的代码实际上就是**一个神经元进行前向传播(forward-propagating)的过程**。\n",
    "\n",
    "单个神经元可以用来实现**二分类器**，比如**Binary Softmax Classifier(Logistic regression)** 和**Binary SVM Classifier**。\n",
    "我们使用**交叉熵损失**，就实现了一个**Binary Softmax Classifier**，使用**hinge loss**就实现了一个**Binary SVM Classifier**。\n",
    "\n",
    "## 常用的激活函数(activation function)\n",
    "**激活函数(activation function or non-linearity)**　对于每一个输入，都进行一个相同的固定的数学计算。\n",
    "常见的激活函数有：\n",
    "\n",
    "* Sigmoid. $\\sigma(x)=\\frac{1}{1+e^{-x}}$\n",
    "* Tanh. $tanh(x)=2\\sigma(2x)-1$\n",
    "* ReLU. $f(x)=max(0,x)$\n",
    "* Leaky ReLU. $f(x) = \\mathbb{1}(x < 0) (\\alpha x) + \\mathbb{1}(x>=0) (x)$\n",
    "* Maxout. $f(x,w_1,w_2)=\\max(w_1^Tx+b_1, w_2^Tx + b_2)$\n",
    "\n",
    "**Sigmoid**函数大家肯定很熟悉了。它对每一个输入都压缩到(0,1)区间。历史上sigmoid函数用的很多，因为它很好地解释了神经元的firing rate。但是现在基本上都**避免使用sigmoid**作为激活函数。\n",
    "![](images/sigmoid.jpeg)\n",
    "它有两个主要的缺点。\n",
    "\n",
    "* 梯度消失。因为靠近0和1的地方，梯度在这些区域几乎为0。\n",
    "* 不是以0为中心。假设输出给下一个神经元的数据，一直是正数，那么反向传播过程中的梯度也会是一直是正数。这会影响梯度下降。\n",
    "\n",
    "**Tanh**函数形状和**Sigmoid**很像，它把输入压缩到(-1, 1)的区间，并且是以0为中心的。因此，实际使用中，tanh总是应该优先于sigmoid。实际上，tanh函数是sigmoid函数的一个缩放，如它的公式。\n",
    "![](images/tanh.jpeg)\n",
    "\n",
    "**ReLU(Reatified Linear Unit)** 函数在小于0的地方一直等于0，大于0的地方等于x。\n",
    "![](images/relu.jpeg)\n",
    "它的优点如下：\n",
    "\n",
    "* 收敛速度相对于sigmoid/tanh来说快很多。\n",
    "* 避免了sigmoid/tanh中的指数操作。\n",
    "\n",
    "当然，它也有缺点：\n",
    "\n",
    "* 如果learning rate设置不好(通常来说是太大了)，可能会导致\"ReLU units can be fragile during training and can “die”.\"\n",
    "\n",
    "**Leaky ReLU**是**ReLU**的改良版，它对ReLU小于0的部分做出修正：将0改成一个很小的常熟。这个从它的公式就可以看出来。\n",
    "\n",
    "**Maxout**是ReLu和Leaky ReLU的通用形式，从公式可以看出来，ReLU和Leaky ReLU是它的一个特例。比如，使$w_1,b_1=0$，maxout就变成了ReLU。**Maxout**继承了ReLU的所有优点，但是**缺点**就是它使得参数增加了一倍。\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 神经网络的结构\n",
    "\n",
    "神经网络结构中最常见的一种就是**全连接层fully-connected layer**了。下面两张图分别展示了一个2层的全连接网络和一个3层的全连接网络。\n",
    "\n",
    "![2_layer_net](images/neural_net_fully_connected_2_layers.jpeg)\n",
    "![3_layer_net](images/neural_net_fully_connected_3_layers.jpeg)\n",
    "\n",
    "当我们说一个N层的网络的时候，我们一般不包括**输入层**。因此，对于一个单层网络，实际上有两层：一个**输入层**和一个**输出层**，没有**隐藏层**。所以，可以把**Logistic regression**或者**SVMs**说成是**单层神经网络**。\n",
    "\n",
    "**输出层**：输出层比较特殊，它一般**没有激活函数**。这是因为，最后的输出层一般用来表示**分数**，这个分数在分类问题里面就是类别，在回归里面就是预测值。\n",
    "\n",
    "如何衡量神经网络的大小呢？\n",
    "一般来说，两种方式。一种是**神经元的个数**，一种是**参数的个数**。\n",
    "\n",
    "现在有一个问题：对于任何一个函数，我们都可以用神经网络来建模吗？\n",
    "实际上，**对于任何连续函数f(x)，都存在可以含有一个隐藏层的神经网络可以无限逼近这个函数**。也就是说，**神经网络可以逼近任意函数**。\n",
    "\n",
    "那含有一个隐藏层的神经网络可以逼近任意函数，我们为什么需要更深的神经网络呢？\n",
    "答案很简单：**实践出真知。实际上深度网络的效果更好，虽然这两种网络的表示能力是一样的**！\n",
    "\n",
    "\n",
    "那么对于一个实际问题，我们应该怎么决定**用多少个隐藏层**，**每个隐藏层应该是多少个神经单元**呢？\n",
    "对于不是很复杂的数据，如果使用大的网络，可以很好地拟合训练数据，但是有可能会出现**过拟合**。\n",
    "\n",
    "所以，对于不是很复杂的数据，我们就应该倾向于**小网络**吗？答案是：No!\n",
    "实际上，我们宁愿使得网络设计地大一些，然后通过其他手段来防止过拟合。比如(**正则化**，**Dropout**，**输入噪声**)等等。\n"
    ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
